/**
 * 
 */
package com.vivid.dynamics.oknow.model;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 *
 * @author jason
 * created at:: Jul 27, 2011 4:48:42 PM
 */
public class User {
	private int id;
	private String firstName;
	private String lastName;
	private boolean admin;
	private String parentHierarchyTree;
	//private int themeId;
	private String email;
	private String backupEmail;
	/*
	 *  at this moment... should only exist "1" group per user...
	 */
	private List<Group> groups;
	
	// remove after adding the real entities and its functions	
	//@Transient
	private Set<Permission> permissions;
	private UserTheme userTheme;
	private List<Bookmark> bookmarks;
	private List<UserCategory> userCategories;
	
	/**
	 * ctor. for hibernate
	 */
	protected User() {}
	
	/**
	 * ctor. Except id and userTheme, all the fields can be provided. 
	 * Handling on the missing UserTheme???
	 * @param pFirstName
	 * @param pLastName
	 * @param pIsAdmin
	 * @param pParentHierarchyTree
	 * @param pEmail
	 * @param pBackupEmail
	 */
	public User(String pFirstName, String pLastName, boolean pIsAdmin,
		String pParentHierarchyTree, String pEmail,
		String pBackupEmail) {
		super();
		this.firstName = pFirstName;
		this.lastName = pLastName;
		this.admin = pIsAdmin;
		this.parentHierarchyTree = pParentHierarchyTree;
		//this.themeId = pThemeId;
		this.email = pEmail;
		this.backupEmail = pBackupEmail;
	}

	/**
	 * <b>PS</b>. a MUST for hibernate entities, or you will have problems 
	 * during association methods; simply you can't remove / update the correct
	 * logical Entity in your collections<p/>
	 * {@inheritDoc}
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + id;
		/*
		result = prime * result + (admin ? 1231 : 1237);
		result = prime * result
				+ ((backupEmail == null) ? 0 : backupEmail.hashCode());
		result = prime * result + ((email == null) ? 0 : email.hashCode());
		result = prime * result
				+ ((firstName == null) ? 0 : firstName.hashCode());
		result = prime * result
				+ ((lastName == null) ? 0 : lastName.hashCode());
		result = prime
				* result
				+ ((parentHierarchyTree == null) ? 0 : parentHierarchyTree
						.hashCode());
		 */						
		return result;
	}

	/**
	 * <b>PS</b>. a MUST for hibernate entities, or you will have problems 
	 * during association methods; simply you can't remove / update the correct
	 * logical Entity in your collections<p/>
	 * {@inheritDoc}
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		User other = (User) obj;
		if (admin != other.admin)
			return false;
		if (backupEmail == null) {
			if (other.backupEmail != null)
				return false;
		} else if (!backupEmail.equals(other.backupEmail))
			return false;
		if (email == null) {
			if (other.email != null)
				return false;
		} else if (!email.equals(other.email))
			return false;
		if (firstName == null) {
			if (other.firstName != null)
				return false;
		} else if (!firstName.equals(other.firstName))
			return false;
		if (id != other.id)
			return false;
		if (lastName == null) {
			if (other.lastName != null)
				return false;
		} else if (!lastName.equals(other.lastName))
			return false;
		if (parentHierarchyTree == null) {
			if (other.parentHierarchyTree != null)
				return false;
		} else if (!parentHierarchyTree.equals(other.parentHierarchyTree))
			return false;
		return true;
	}

	/**
	 * 
	 */
	@Override
	public String toString() {
		return "User [id=" + id + ", firstName=" + firstName + ", lastName="
			+ lastName + ", isAdmin=" + admin + ", parentHierarchyTree="
			+ parentHierarchyTree + ", email=" + email 
			+ ", backupEmail=" + backupEmail + "]";
	}

	/* ************************ */
	/* *   accessor/mutator   * */
	/* ************************ */
	
	/**
	 * 
	 * @return
	 * @author jason
	 * created at:: Jul 27, 2011  4:54:49 PM
	 */
	public String getFirstName() {
		return firstName;
	}
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	/**
	 * 
	 * @return
	 * @author jason
	 * created at:: Jul 27, 2011  4:55:15 PM
	 */
	public String getLastName() {
		return lastName;
	}
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	/**
	 * 
	 * @return
	 * @author jason
	 * created at:: Jul 27, 2011  4:55:20 PM
	 */
	public boolean isAdmin() {
		return admin;
	}
	public void setAdmin(boolean isAdmin) {
		this.admin = isAdmin;
	}

	/**
	 * 
	 * @return
	 * @author jason
	 * created at:: Jul 27, 2011  4:55:24 PM
	 */
	public String getParentHierarchyTree() {
		return parentHierarchyTree;
	}
	public void setParentHierarchyTree(String parentHierarchyTree) {
		this.parentHierarchyTree = parentHierarchyTree;
	}

	/*
	 * 
	 * @return
	 * @author jason
	 * created at:: Jul 27, 2011  4:55:30 PM
	 *
	public int getThemeId() {
		return themeId;
	}
	public void setThemeId(int themeId) {
		this.themeId = themeId;
	}*/

	/**
	 * 
	 * @return
	 * @author jason
	 * created at:: Jul 27, 2011  4:55:35 PM
	 */
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}

	/**
	 * 
	 * @return
	 * @author jason
	 * created at:: Jul 27, 2011  4:55:40 PM
	 */
	public String getBackupEmail() {
		return backupEmail;
	}
	public void setBackupEmail(String backupEmail) {
		this.backupEmail = backupEmail;
	}

	/**
	 * 
	 * @return
	 * @author jason
	 * created at:: Jul 27, 2011  4:55:45 PM
	 */
	public int getId() {
		return id;
	}
	protected void setId(int pId) {
		this.id=pId;
	}

	/**
	 * 
	 * @return
	 * @author jason
	 * created at:: Jul 28, 2011  11:25:02 AM
	 */
	public List<Group> getGroups() {
		if (this.groups==null) {
			this.groups=new ArrayList<Group>();
		}
		return groups;
	}
	protected void setGroups(List<Group> groups) {
		this.groups = groups;
	}
	/**
	 * 
	 * @return
	 * @author jason
	 * created at:: Jul 28, 2011  11:28:24 AM
	 */
	public Set<Permission> getPermissions() {
		if (this.permissions==null) {
			this.permissions=new HashSet<Permission>();
		}
		return permissions;
	}
	protected void setPermissions(Set<Permission> permissions) {
		this.permissions = permissions;
	}
	/**
	 * 
	 * @return
	 * @author jason
	 * created at:: Jul 28, 2011  11:29:06 AM
	 */
	public UserTheme getUserTheme() {
		return userTheme;
	}
	public void setUserTheme(UserTheme userTheme) {
		this.userTheme = userTheme;
	}
	
	/**
	 * 
	 * @return
	 * @author jason
	 * created at:: Jul 28, 2011  11:30:18 AM
	 */
	public List<Bookmark> getBookmarks() {
		if (this.bookmarks==null) {
			this.bookmarks=new ArrayList<Bookmark>();
		}
		return bookmarks;
	}
	protected void setBookmarks(List<Bookmark> bookmarks) {
		this.bookmarks = bookmarks;
	}
	
	/**
	 * 
	 * @return
	 * @author jason
	 * created at:: Aug 12, 2011  3:34:01 PM
	 */
	public List<UserCategory> getUserCategories() {
		if (this.userCategories==null) {
			this.userCategories=new ArrayList<UserCategory>();
		}
		return userCategories;
	}
	public void setUserCategories(List<UserCategory> userCategories) {
		this.userCategories = userCategories;
	}	

	/* ********************************* */
	/* *     association method(s)     * */
	/* ********************************* */


	/**
	 * convenient method for adding a new Group; since User is the 
	 * owner... it controls on both ends' association
	 * @param pGroup
	 * @author jason
	 * created at:: Jul 29, 2011  11:51:09 AM
	 */
	public void addGroup(final Group pGroup) {
		if (pGroup!=null) {
			// add to "this"
			this.getGroups().add(pGroup);
			
			// update the "group"
			pGroup.getUsers().add(this);
		}
	}
	/**
	 * convenient method for removing a group from this USER instance; 
	 * since User is the owner... it controls on both ends' association<p/>
	 * <b>PS</b>. modification of Group simply = <b>1)</b> remove to be modified group,
	 * <b>2)</b> add the new group pointing to the targeted group
	 * @param pGroup
	 * @author jason
	 * created at:: Jul 29, 2011  2:31:04 PM
	 */
	public void removeGroup(final Group pGroup) {
		if (pGroup!=null) {
			// remove it from "this"
			this.getGroups().remove(pGroup);
			
			// update the "group"
			pGroup.getUsers().remove(this);
		}
	}
	
	/**
	 * convenient method for adding a Bookmark to both sides of the 
	 * relation.
	 * <ul>
	 * 	<li>User</li>
	 * 	<li>Bookmark</li>
	 * </ul>
	 * @param pBMark
	 * @author jason
	 * created at:: Aug 4, 2011  11:47:44 AM
	 */
	public void addBookmark(final Bookmark pBMark) {
		if (pBMark!=null) {
			// add to "this"
			this.getBookmarks().add(pBMark);
			
			// update the "bookmark"
			pBMark.setUser(this);
		}
	}
	
	/**
	 * convenient method for removing a Bookmark from both sides of the 
	 * relation.
	 * <ul>
	 * 	<li>User</li>
	 * 	<li>Bookmark</li>
	 * </ul>
	 * <b>PS</b>. HOWEVER, since the table schema has set the UserId as FK, 
	 * caller/manager MUST remove the Bookmark instance/entity afterwards... 
	 * or else... any update MIGHT have 
	 * <ul>
	 * 	<li>Exception on db-constraints</li>
	 * 	<li>Orphaned data... unless you configured the cascade-delete options and delete-orphan options for Hibernate</li>
	 * </ul>
	 * @param pBMark
	 * @author jason
	 * created at:: Aug 4, 2011  11:49:57 AM
	 */
	public void removeBookmark(final Bookmark pBMark) {
		if (pBMark!=null) {
			// remove from "this"
			this.getBookmarks().remove(pBMark);
			
			// update the "bookmark"
			pBMark.setUser(null);
		}
	}
	
	/**
	 * convenient method to add a Permission to the User. However since 
	 * this is a uni-directional relationship... only 1 side will be
	 * updated eventually.
	 * <ul>
	 * 	<li>User</li>
	 * 	<li>
	 * 		Permission <!-- <b>WILL NOT</b> have any special association, 
	 *		since this is a uni-directional relationship; 
	 *		PLUS "user" is the owner -->
	 *	</li>
	 * </ul>
	 * @param pPer
	 * @author jason
	 * created at:: Aug 5, 2011  11:00:23 AM
	 */
	public void addPermission(final Permission pPer) {
		if (pPer!=null) {
			// add to "this"
			this.getPermissions().add(pPer);
			// update the reference to "pPer" .. if required
			pPer.setUser(this);
		}
	}
	
	/**
	 * convenient method to remove a Permission from the User. However since 
	 * this is a uni-directional relationship... only 1 side will be
	 * updated eventually.
	 * <ul>
	 * 	<li>User</li>
	 * 	<li>
	 * 		Permission <!-- <b>WILL NOT</b> have any special association, 
	 *		since this is a uni-directional relationship; 
	 *		PLUS "user" is the owner -->
	 *	</li>
	 * </ul>
	 * @param pPer
	 * @author jason
	 * created at:: Aug 5, 2011  11:03:40 AM
	 */
	public void removePermission(final Permission pPer) {
		if (pPer!=null) {
			// update "this"
			this.getPermissions().remove(pPer);
			// update the pPer .. if required
			pPer.setUser(null);
		}
	}
	
	/**
	 * convenient method to add a UserCategory to the User. However since 
	 * this is a uni-directional relationship... only 1 side will be
	 * updated eventually.
	 * <ul>
	 * 	<li>User</li>
	 * 	<li>UserCategory</li>
	 * </ul>
	 * @param pCat
	 * @author jason
	 * created at:: Aug 12, 2011  3:35:51 PM
	 */
	public void addUserCategory(final UserCategory pCat) {
		if (pCat!=null) {
			// update "this"
			this.getUserCategories().add(pCat);
			
			// update the pCat
			pCat.setUser(this);
		}
	}
	
	/**
	 * convenient method to remove a UserCategory from the User. However since 
	 * this is a uni-directional relationship... only 1 side will be
	 * updated eventually.
	 * <ul>
	 * 	<li>User</li>
	 * 	<li>UserCategory</li>
	 * </ul>
	 * @param pCat
	 * @author jason
	 * created at:: Aug 12, 2011  3:35:51 PM
	 */	
	public void removeUserCategory(final UserCategory pCat) {
		if (pCat!=null) {
			// update "this"
			this.getUserCategories().remove(pCat);
			
			// update pCat
			pCat.setUser(null);
		}
	}
	
}
